﻿using Microsoft.Phone.Maps.Controls;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;

namespace YellowMap
{
    [DataContract()]
    public class GoogleDirectionResponse
    {

        #region DecodePolylinePoints
        public static List<LocationPoint> DecodePolylinePoints(string encodedPoints)
        {
            if (encodedPoints == null || encodedPoints == "") return null;
            List<LocationPoint> poly = new List<LocationPoint>();
            char[] polylinechars = encodedPoints.ToCharArray();
            int index = 0;

            int currentLat = 0;
            int currentLng = 0;
            int next5bits;
            int sum;
            int shifter;

            try
            {
                while (index < polylinechars.Length)
                {
                    // calculate next latitude
                    sum = 0;
                    shifter = 0;
                    do
                    {
                        next5bits = (int)polylinechars[index++] - 63;
                        sum |= (next5bits & 31) << shifter;
                        shifter += 5;
                    } while (next5bits >= 32 && index < polylinechars.Length);

                    if (index >= polylinechars.Length)
                        break;

                    currentLat += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1);

                    //calculate next longitude
                    sum = 0;
                    shifter = 0;
                    do
                    {
                        next5bits = (int)polylinechars[index++] - 63;
                        sum |= (next5bits & 31) << shifter;
                        shifter += 5;
                    } while (next5bits >= 32 && index < polylinechars.Length);

                    if (index >= polylinechars.Length && next5bits >= 32)
                        break;

                    currentLng += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1);
                    LocationPoint p = new LocationPoint();
                    p.Latitude = Convert.ToDouble(currentLat) / 100000.0;
                    p.Longtitude = Convert.ToDouble(currentLng) / 100000.0;
                    poly.Add(p);
                }
            }
            catch (Exception ex)
            {
                // logo it
            }
            return poly;
        }



        #endregion


        public static GoogleDirectionResponse ParseFromJSON(String jsonData)
        {
            // jsonData = jsonData.Replace("\"routes\" : [", "\"routes\" : {");
            // jsonData = jsonData.Replace("],\n   \"status\"", "},\n   \"status\"");
            GoogleDirectionResponse output;
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(GoogleDirectionResponse));
            using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(jsonData)))
            {
                output = serializer.ReadObject(stream) as GoogleDirectionResponse;
            }
            return output;
        }

        public MapPolyline GetMapPolyline() {
            MapPolyline mpl = new MapPolyline();
            mpl.StrokeThickness = Constant.MAP_POLYLINE_THICNESS;
            mpl.StrokeColor = Constant.MAP_POLYLINE_COLOR;
            var points = this.Routes[0].OverviewPolyline.Points;
            foreach (var point in points)
            {
                mpl.Path.Add(new System.Device.Location.GeoCoordinate(point.Latitude, point.Longtitude));
            }
            return mpl;
        }

        [DataMember(Name = "routes")]
        public List<route> Routes { get; set; }

        [DataMember(Name = "status")]
        public string Status { get; set; }

        [DataContract()]
        public class route
        {
            [DataMember(Name = "copyrights")]
            public string copyrights { get; set; }

            [DataMember(Name = "legs")]
            public List<leg> Legs { get; set; }

            [DataMember(Name = "overview_polyline")]
            public polyline OverviewPolyline { get; set; }

            [DataMember(Name = "summary")]
            public string Summary { get; set; }

            [DataContract()]
            public class leg
            {
                [DataMember(Name = "distance")]
                public distance Distance { get; set; }

                [DataMember(Name = "duration")]
                public duration Duration { get; set; }

                [DataMember(Name = "start_address")]
                public string StartAddress { get; set; }

                [DataMember(Name = "end_address")]
                public string EndAddress { get; set; }

                [DataMember(Name = "end_location")]
                public LatLng EndLocation { get; set; }

                [DataMember(Name = "start_location")]
                public LatLng StartLocation { get; set; }

                [DataMember(Name = "steps")]
                public List<step> Steps { get; set; }


                [DataContract()]
                public class step
                {
                    [DataMember(Name = "distance")]
                    public distance Distance { get; set; }

                    [DataMember(Name = "duration")]
                    public duration Duration { get; set; }

                    [DataMember(Name = "end_location")]
                    public LatLng EndLocation { get; set; }

                    [DataMember(Name = "start_location")]
                    public LatLng StartLocation { get; set; }

                    [DataMember(Name = "travel_mode")]
                    public string TravelMode { get; set; }

                    string _html_instructions;
                    [DataMember(Name = "html_instructions")]
                    public string HtmlInstructions
                    {
                        get { return _html_instructions; }
                        set
                        {

                            _html_instructions = StripHTML(System.Net.HttpUtility.HtmlDecode(value));
                        }
                    }

                    string StripHTML(string str)
                    {
                        str = str.Replace("<div style=\"font-size:0.9em\">", ". ");
                        str = str.Replace("<\\div>", "");
                        return System.Text.RegularExpressions.Regex.Replace(str, @"<(.|\n)*?>", " ") ;
                    }

                    [DataMember(Name = "polyline")]
                    public polyline Polyline { get; set; }

                }

                [DataContract()]
                public class distance
                {
                    [DataMember(Name = "text")]
                    public string Text { get; set; }
                    [DataMember(Name = "value")]
                    public double Value { get; set; }
                }
                [DataContract()]
                public class duration
                {
                    [DataMember(Name = "text")]
                    public string Text { get; set; }
                    [DataMember(Name = "value")]
                    public double Value { get; set; }
                }
            }
        }

    }

    [DataContract()]
    public class LatLng
    {
        [DataMember(Name = "lat")]
        public double Lattitude { get; set; }
        [DataMember(Name = "lng")]
        public double Longtitude { get; set; }
    }

    [DataContract()]
    public class polyline
    {
        [DataMember(Name = "points")]
        public string PointsCode { get; set; }

        public List<LocationPoint> Points
        {
            get
            {
                return GoogleDirectionResponse.DecodePolylinePoints(PointsCode);
            }
        }
    }

    public class LocationPoint
    {
        public double Latitude { get; set; }
        public double Longtitude { get; set; }
    }

    
}
